home *** CD-ROM | disk | FTP | other *** search
/ Ham Radio 2000 #1 / Ham Radio 2000.iso / ham2000 / hf / dsp / dsp4tool / spectrum.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-25  |  13.9 KB  |  531 lines

  1. /*  SPECTRUM.C - Displays Specrum of Given Signal (Data)
  2.  *
  3.  *  Copyright (C) 1988, 1989 by J Vuori. All rights reserved.
  4.  *  Author(s): J Vuori
  5.  *  Modification(s):
  6.  */
  7.  
  8. #define  NOMINMAX    // because they are defined in stdlib.h
  9. #include <windows.h>
  10. #include <math.h>
  11. #include <stdlib.h>
  12. #include <memory.h>
  13. #include <string.h>
  14. #include "music.h"
  15. #include "fft.h"
  16.  
  17. /* parameters */
  18. #define WINDOW_CLASS     "spectrum"
  19. #define FFTLOGLEN     8
  20. #define VERTICALTICKS     5
  21. #define HORISONTALTICKS  4
  22.  
  23. /* internal contants */
  24. #define FFTLEN         (1 << FFTLOGLEN)
  25. #define DATAPROP     "hData"    /* id names of window properties */
  26. #define TRANSFORMEDPROP  "hXformed"
  27. #define SELECTIONPROP     "hSelect"
  28. #define IDMPRINTSPECTRUM 10        /* menu id's */
  29. #define IDMNONE      11
  30. #define IDMHANNING     12
  31. #define IDMHAMMING     13
  32. #define IDMBLACKMAN     14
  33.  
  34.  
  35. long FAR PASCAL SpectrumProc(HWND, unsigned, WORD, LONG);
  36.  
  37. /* Initialize Spectrum Analyzer */
  38. BOOL SpectrumInit(hInstance)
  39. HANDLE hInstance;
  40. {
  41.     WNDCLASS wcClass;
  42.  
  43.     wcClass.hCursor      = LoadCursor(NULL, IDC_ARROW);
  44.     wcClass.hIcon      = 0;
  45.     wcClass.lpszMenuName  = (LPSTR) 0;
  46.     wcClass.lpszClassName = (LPSTR) WINDOW_CLASS;
  47.     wcClass.hbrBackground = GetStockObject(WHITE_BRUSH);
  48.     wcClass.hInstance      = hInstance;
  49.     wcClass.style      = CS_VREDRAW | CS_HREDRAW;
  50.     wcClass.lpfnWndProc   = SpectrumProc;
  51.     wcClass.cbClsExtra      = 0;
  52.     wcClass.cbWndExtra      = 0;
  53.     if (!RegisterClass((LPWNDCLASS) &wcClass))
  54.     return FALSE;
  55.  
  56.     return TRUE;
  57. }
  58.  
  59.  
  60. /* Activate Spectrum Analyzer */
  61. BOOL Spectrum(hWnd, Name, pprocSource)
  62. HWND     hWnd;
  63. char    *Name;
  64. double (*pprocSource)(unsigned);
  65. {
  66.     HMENU      hMenuMain, hMenuPopup;
  67.     HWND       hWndSpectrum, hWndPrev;
  68.     HDC        hDC;
  69.     TEXTMETRIC tmFontInfo;
  70.     RECT       rcWnd;
  71.     HANDLE     hOrigData, hXformed;
  72.     int        X, Y, height, lenght;
  73.  
  74.     /* check if there are already display of the same source */
  75.     if(hWndSpectrum = FindWindow((LPSTR) WINDOW_CLASS, (LPSTR) Name))
  76.     {
  77.     /* yes, update it only */
  78.     hOrigData = GetProp(hWndSpectrum, (LPSTR) DATAPROP);
  79.     hXformed  = GetProp(hWndSpectrum, (LPSTR) TRANSFORMEDPROP);
  80.     FetchData(hOrigData, pprocSource);
  81.     TransformData(hWndSpectrum, hOrigData, hXformed);
  82.     InvalidateRect(hWndSpectrum, (LPRECT) NULL, TRUE);
  83.     } else
  84.     {
  85.     /* no, create a new one */
  86.     /* first allocate memory for local usage */
  87.     if(!(hOrigData = LocalAlloc(LMEM_MOVEABLE, FFTLEN * sizeof(double))))
  88.         return FALSE;
  89.     if(!(hXformed  = LocalAlloc(LMEM_MOVEABLE, FFTLEN * sizeof(struct complex))))
  90.     {
  91.         LocalFree(hOrigData);
  92.         return FALSE;
  93.     }
  94.  
  95.     /* create menu */
  96.     hMenuMain = CreateMenu();
  97.     ChangeMenu(hMenuMain, NULL, (LPSTR) "Print", IDMPRINTSPECTRUM, MF_APPEND);
  98.  
  99.     hMenuPopup = CreateMenu();
  100.     ChangeMenu(hMenuPopup, NULL, (LPSTR) "None",     IDMNONE,     MF_APPEND);
  101.     ChangeMenu(hMenuPopup, NULL, (LPSTR) "Hanning",  IDMHANNING,  MF_APPEND);
  102.     ChangeMenu(hMenuPopup, NULL, (LPSTR) "Hamming",  IDMHAMMING,  MF_APPEND);
  103.     ChangeMenu(hMenuPopup, NULL, (LPSTR) "Blackman", IDMBLACKMAN, MF_APPEND);
  104.  
  105.     ChangeMenu(hMenuMain,  NULL, (LPSTR) "Windows",  hMenuPopup,  MF_APPEND | MF_BYCOMMAND | MF_POPUP);
  106.  
  107.     /* calculate windows dimensions */
  108.     hDC = GetDC(NULL);
  109.     GetTextMetrics(hDC, (LPTEXTMETRIC) &tmFontInfo);
  110.     ReleaseDC(NULL, hDC);
  111.  
  112.     /* analyze where to put it */
  113.     if(hWndPrev = FindWindow((LPSTR) WINDOW_CLASS, (LPSTR) NULL))
  114.     {
  115.         /* there are previous windows, stack it on the top of them */
  116.         GetWindowRect(hWndPrev, (LPRECT) &rcWnd);
  117.         height = rcWnd.bottom - rcWnd.top;
  118.         lenght = rcWnd.right  - rcWnd.left;
  119.  
  120.         X = rcWnd.left + GetSystemMetrics(SM_CXVSCROLL);
  121.         Y = rcWnd.top  + GetSystemMetrics(SM_CYHSCROLL);
  122.     } else
  123.     {
  124.         /* it is first window (of its class) put it to the right of parent window */
  125.         GetWindowRect(hWnd, (LPRECT) &rcWnd);
  126.         height = 14 * tmFontInfo.tmHeight;
  127.         lenght = 30 * tmFontInfo.tmAveCharWidth;
  128.  
  129.         X = rcWnd.right + GetSystemMetrics(SM_CXVSCROLL);
  130.         Y = rcWnd.top   + (rcWnd.bottom - rcWnd.top) / 2 - height / 2;
  131.     }
  132.  
  133.     /* create window to center of parent window */
  134.     hWndSpectrum = CreateWindow(
  135.         (LPSTR) WINDOW_CLASS,           /* window class name           */
  136.         (LPSTR) Name,               /* name appearing in window caption */
  137.         WS_SIZEBOX | WS_CAPTION |
  138.         WS_SYSMENU | WS_POPUP,           /* style                */
  139.         X,                       /*   x : ignored for tiled window   */
  140.         Y,                       /*   y : ignored for tiled window   */
  141.         lenght,                   /*  cx : ignored for tiled window   */
  142.         height,                   /*  cy : ignored for tiled window   */
  143.         hWnd,                   /*  parent window           */
  144.         hMenuMain,                   /*  menu, or child window id       */
  145.         (HANDLE)hInstMusic,            /*  handle to window instance       */
  146.         (LPSTR) NULL               /*  params to pass on           */
  147.         );
  148.  
  149.     /* set datawindow selection to deterministic state */
  150.     InitializeSelection(hWndSpectrum);
  151.  
  152.     /* get data from source and put handle to windows context */
  153.     FetchData(hOrigData, pprocSource);
  154.     TransformData(hWndSpectrum, hOrigData, hXformed);
  155.     SetProp(hWndSpectrum, (LPSTR) DATAPROP,        hOrigData);
  156.     SetProp(hWndSpectrum, (LPSTR) TRANSFORMEDPROP, hXformed);
  157.  
  158.     /* display edit control */
  159.     ShowWindow(hWndSpectrum, SHOW_OPENWINDOW);
  160.     }
  161.  
  162.     UpdateWindow(hWndSpectrum);
  163.  
  164.     return (TRUE);
  165. }
  166.  
  167.  
  168. /* Spectrum Class Procedure */
  169. long FAR PASCAL SpectrumProc(hWnd, message, wParam, lParam)
  170. HWND     hWnd;
  171. unsigned message;
  172. WORD     wParam;
  173. LONG     lParam;
  174. {
  175.     PAINTSTRUCT ps;
  176.  
  177.     switch (message)
  178.     {
  179.     case WM_COMMAND:
  180.     SpectrumCommand(hWnd, wParam);
  181.     break;
  182.  
  183.     case WM_PAINT:
  184.     BeginPaint(hWnd, (LPPAINTSTRUCT) &ps);
  185.     DrawSpectrum(hWnd, ps.hdc);
  186.     ValidateRect(hWnd, (LPRECT) NULL);
  187.     EndPaint(hWnd, (LPPAINTSTRUCT) &ps);
  188.     break;
  189.  
  190.     case WM_MOUSEMOVE:
  191.     ChkCursor();
  192.     break;
  193.  
  194.     case WM_CLOSE:
  195.     DeleteSpectrumProps(hWnd);
  196.     break;
  197.  
  198.     default:
  199.     return((long)DefWindowProc(hWnd, message, wParam, lParam));
  200.     break;
  201.     }
  202.  
  203.     return(0L);
  204. }
  205.  
  206.  
  207. /* initialize menu selections */
  208. static InitializeSelection(hWnd)
  209. HWND hWnd;
  210. {
  211.     HANDLE  hSelection;
  212.     int    *pSelection;
  213.  
  214.     /* set menu selection */
  215.     hSelection    = LocalAlloc(LMEM_MOVEABLE, sizeof(int));
  216.     pSelection    = (int *) LocalLock(hSelection);
  217.     *pSelection = 0;
  218.     CheckMenuItem(GetMenu(hWnd), IDMNONE+0, MF_CHECKED);
  219.     LocalUnlock(hSelection);
  220.     SetProp(hWnd, (LPSTR) SELECTIONPROP, hSelection);
  221. }
  222.  
  223. /* get data from source */
  224. static FetchData(hPropData, pprocSource)
  225. HANDLE     hPropData;
  226. double (*pprocSource)(unsigned);
  227. {
  228.     double          *p;
  229.     register unsigned  i;
  230.  
  231.     p = (double *) LocalLock(hPropData);
  232.  
  233.     /* get data from source */
  234.     Waiting();
  235.     for(i = 0; i < FFTLEN; i++)
  236.     *p++ = (*pprocSource) (i);
  237.     Ready();
  238.  
  239.     LocalUnlock(hPropData);
  240. }
  241.  
  242.  
  243. /* modify data with window, then fourier transform it */
  244. static TransformData(hWnd, hPropData, hXformData)
  245. HWND   hWnd;
  246. HANDLE hPropData, hXformData;
  247. {
  248.     struct complex *pData;
  249.     double       *pOrig;
  250.  
  251.     pOrig     = (double *)       LocalLock(hPropData);
  252.     pData     = (struct complex *) LocalLock(hXformData);
  253.  
  254.     Waiting();
  255.     FFTWindow(hWnd, pData, pOrig, FFTLOGLEN);
  256.     fft(pData, FFTLOGLEN);
  257.     Ready();
  258.  
  259.     LocalUnlock(hXformData);
  260.     LocalUnlock(hPropData);
  261. }
  262.  
  263.  
  264. /* initialize printing */
  265. int PrintInit(hWnd, hDC, s)
  266. HWND  hWnd;
  267. HDC   hDC;
  268. char *s;
  269. {
  270.     POINT ptPageSize;
  271.  
  272.     /* display spectrum as 4/5, 1/3 of original size */
  273.     SetMapMode(hDC, MM_ANISOTROPIC);
  274.  
  275.     SetWindowOrg(hDC, -75,  115);
  276.     SetWindowExt(hDC, 607, -130);
  277.  
  278.     Escape(hDC, GETPHYSPAGESIZE, 0, (LPSTR) NULL, (LPSTR) &ptPageSize);
  279.  
  280.     SetViewportOrg(hDC, 0, 0);
  281.     SetViewportExt(hDC, 4 * ptPageSize.x / 5, 1 * ptPageSize.y / 3);
  282.  
  283.     strcpy(s, "FFT Spectrum");
  284.     return(1);    /* only one page */
  285. }
  286.  
  287.  
  288. /* print one (and only) page */
  289. void PrintPage(hWnd, hDC, PageCnt)
  290. HWND hWnd;
  291. HDC  hDC;
  292. int  PageCnt;
  293. {
  294.     HANDLE        hXformed;
  295.     LONG        TextExt;
  296.     struct complex *pData;
  297.     double        MaxValue;
  298.     char        buff[32];
  299.  
  300.     hXformed = GetProp(hWnd, (LPSTR) TRANSFORMEDPROP);
  301.     pData    = (struct complex *) LocalLock(hXformed);
  302.  
  303.     SetWindowOrg(hDC, -75,  115);
  304.     SetWindowExt(hDC, 607, -130);
  305.  
  306.     MaxValue = DetermineMaxValue(pData, FFTLOGLEN);
  307.     DrawAxes(hDC, MaxValue);
  308.     DrawValues(hDC, pData, MaxValue);
  309.  
  310.     /* Write Spectrums Name */
  311.     GetWindowText(hWnd, (LPSTR) buff, sizeof(buff));
  312.     TextExt = GetTextExtent(hDC, (LPSTR) buff, strlen(buff));
  313.     TextOut(hDC, (512 - LOWORD(TextExt)) / 2, 110, (LPSTR) buff, strlen(buff));
  314.  
  315.     LocalUnlock(hXformed);
  316. }
  317.  
  318.  
  319. /* do menu command */
  320. static SpectrumCommand(hWnd, wParam)
  321. HWND hWnd;
  322. WORD wParam;
  323. {
  324.     HANDLE  hSelection;
  325.     int    *pSelection;
  326.  
  327.     switch (wParam)
  328.     {
  329.     case IDMPRINTSPECTRUM:
  330.     Waiting();
  331.     PrintIt(hWnd, PrintInit, PrintPage);
  332.     Ready();
  333.     break;
  334.  
  335.     case IDMNONE:
  336.     case IDMHAMMING:
  337.     case IDMHANNING:
  338.     case IDMBLACKMAN:
  339.     hSelection  = GetProp(hWnd, (LPSTR) SELECTIONPROP);
  340.     pSelection  = (int *) LocalLock(hSelection);
  341.  
  342.     if(wParam-IDMNONE != *pSelection)
  343.     {
  344.         /* change selection */
  345.         CheckMenuItem(GetMenu(hWnd), IDMNONE + *pSelection, MF_UNCHECKED);
  346.         CheckMenuItem(GetMenu(hWnd), wParam,        MF_CHECKED);
  347.         *pSelection = wParam-IDMNONE;
  348.  
  349.         /* transfrom it */
  350.         TransformData(hWnd, GetProp(hWnd, (LPSTR) DATAPROP), GetProp(hWnd, (LPSTR) TRANSFORMEDPROP));
  351.         InvalidateRect(hWnd, (LPRECT) NULL, TRUE);
  352.     }
  353.  
  354.     LocalUnlock(hSelection);
  355.     break;
  356.  
  357.     default:
  358.     break;
  359.     }
  360. }
  361.  
  362.  
  363. /* free any local window properties */
  364. static DeleteSpectrumProps(hWnd)
  365. HWND hWnd;
  366. {
  367.     LocalFree(GetProp(hWnd, (LPSTR) DATAPROP));        RemoveProp(hWnd, (LPSTR) DATAPROP);
  368.     LocalFree(GetProp(hWnd, (LPSTR) TRANSFORMEDPROP)); RemoveProp(hWnd, (LPSTR) TRANSFORMEDPROP);
  369.     LocalFree(GetProp(hWnd, (LPSTR) SELECTIONPROP));   RemoveProp(hWnd, (LPSTR) SELECTIONPROP);
  370.  
  371.     DestroyWindow(hWnd);
  372. }
  373.  
  374.  
  375. /* print spectrum to window */
  376. static DrawSpectrum(hWnd, hDC)
  377. HWND hWnd;
  378. HDC  hDC;
  379. {
  380.     HANDLE        hXformed;
  381.     RECT        rcClient;
  382.     struct complex *pData;
  383.     double        MaxValue;
  384.  
  385.     hXformed = GetProp(hWnd, (LPSTR) TRANSFORMEDPROP);
  386.     pData    = (struct complex *) LocalLock(hXformed);
  387.  
  388.     SetMapMode(hDC, MM_ANISOTROPIC);
  389.  
  390.     SetWindowOrg(hDC, -75,  115);
  391.     SetWindowExt(hDC, 607, -130);
  392.  
  393.     GetClientRect(hWnd, (LPRECT) &rcClient);
  394.     SetViewportOrg(hDC, 0, 0);
  395.     SetViewportExt(hDC, rcClient.right, rcClient.bottom);
  396.  
  397.     MaxValue = DetermineMaxValue(pData, FFTLOGLEN);
  398.     DrawAxes(hDC, MaxValue);
  399.     DrawValues(hDC, pData, MaxValue);
  400.  
  401.     LocalUnlock(hXformed);
  402. }
  403.  
  404.  
  405. /* adujust current front in hDC so that string s fits in cx,cy rectangle */
  406. static HANDLE AdjustFont(hDC, s, cx, cy)
  407. HDC   hDC;
  408. char *s;
  409. int   cx, cy;
  410. {
  411.     TEXTMETRIC tmFontInfo;
  412.     LOGFONT    lfNewFont;
  413.     LONG       TextExt;
  414.     BOOL       fChange;
  415.  
  416.     GetTextMetrics(hDC, (LPTEXTMETRIC) &tmFontInfo);
  417.     memset(&lfNewFont, 0, sizeof(LOGFONT));
  418.     lfNewFont.lfHeight = tmFontInfo.tmHeight;
  419.     lfNewFont.lfWidth  = tmFontInfo.tmAveCharWidth;
  420.  
  421.     TextExt = GetTextExtent(hDC, (LPSTR) s, strlen(s));
  422.     if (abs(LOWORD(TextExt) - cx) > cx/10)
  423.     {
  424.     lfNewFont.lfWidth  = cx * lfNewFont.lfWidth / LOWORD(TextExt);
  425.     fChange = TRUE;
  426.     }
  427.     if (abs(HIWORD(TextExt) - cy) > cy/10)
  428.     {
  429.     lfNewFont.lfHeight = cy * lfNewFont.lfHeight / HIWORD(TextExt);
  430.     fChange = TRUE;
  431.     }
  432.  
  433.     return(fChange ? CreateFontIndirect((LPLOGFONT) &lfNewFont) : NULL);
  434. }
  435.  
  436.  
  437. /* draw co-oordinate axes */
  438. static DrawAxes(hDC, MaxValue)
  439. HDC    hDC;
  440. double    MaxValue;
  441. {
  442.     HANDLE     hOldFont, hNewFont;
  443.     LONG     TextExt;
  444.     register int x, y;
  445.     char     buff[16];
  446.  
  447.     /* draw axes lines */
  448.     MoveTo(hDC,   0, 100);
  449.     LineTo(hDC,   0,   0);
  450.     LineTo(hDC, 512,   0);
  451.  
  452.     /* check if there are need for smaller font */
  453.     if(hNewFont = AdjustFont(hDC, "XXXXX.X", 75, 15))
  454.     hOldFont = SelectObject(hDC, hNewFont);
  455.  
  456.     /* draw vertical axe with value ticks & labels */
  457.     for(y = 0; y <= 100; y += 100/VERTICALTICKS)
  458.     {
  459.     MoveTo(hDC, -5, y); LineTo(hDC, 0, y);
  460.     sprintf(buff, "%.1lf", (double) y / 100.0 * MaxValue);
  461.     TextExt = GetTextExtent(hDC, (LPSTR) buff, strlen(buff));
  462.     TextOut(hDC, -10-LOWORD(TextExt), y+HIWORD(TextExt)/2, (LPSTR) buff, strlen(buff));
  463.     }
  464.  
  465.     /* draw horisontal axe with value ticks & labels */
  466.     for(x = 0; x <= 512; x += 512/HORISONTALTICKS)
  467.     {
  468.     MoveTo(hDC, x, -2); LineTo(hDC, x, 0);
  469.     sprintf(buff, "%.02lf", (double) x / 512.0);
  470.     TextExt    = GetTextExtent(hDC, (LPSTR) buff, strlen(buff));
  471.     TextOut(hDC, x - LOWORD(TextExt)/2, -4, (LPSTR) buff, strlen(buff));
  472.     }
  473.  
  474.     /* return original font */
  475.     if(hNewFont)
  476.     {
  477.     SelectObject(hDC, hOldFont);
  478.     DeleteObject(hNewFont);
  479.     }
  480. }
  481.  
  482.  
  483. /* draw spectrum plot */
  484. static DrawValues(hDC, pData, MaxValue)
  485. HDC           hDC;
  486. struct complex pData[];
  487. double           MaxValue;
  488. {
  489.     HPEN     hPen, hOldPen;
  490.     register int i;
  491.  
  492.     /* create wider pen */
  493.     hPen    = CreatePen(0, 4, GetTextColor(hDC));
  494.     hOldPen = SelectObject(hDC, hPen);
  495.  
  496.     /* draw datas */
  497.     MoveTo(hDC, 0, (int) (cabs(pData[Bit_Reverse(0, FFTLOGLEN)]) / MaxValue * 100.0));
  498.     for(i = 1; i < FFTLEN / 2; i++)
  499.     LineTo(hDC, i * 4, (int) (cabs(pData[Bit_Reverse(i, FFTLOGLEN)]) / MaxValue * 100.0));
  500.  
  501.     /* restore old pen */
  502.     SelectObject(hDC, hOldPen);
  503.     DeleteObject(hPen);
  504. }
  505.  
  506.  
  507. /* filters data with special windows to resolve discontinuites */
  508. static FFTWindow(hWnd, dest, src, m)
  509. HWND        hWnd;
  510. struct complex *dest;
  511. double           *src;
  512. int        m;
  513. {
  514.     HANDLE      hSelection;
  515.     int      *pSelection;
  516.     static void (*WindowFunctions[]) (struct complex *, double *, int) =
  517.     {
  518.     DirectWin,
  519.     HanningWin,
  520.     HammingWin,
  521.     BlackmanWin
  522.     };
  523.  
  524.     hSelection = GetProp(hWnd, (LPSTR) SELECTIONPROP);
  525.     pSelection = (int *) LocalLock(hSelection);
  526.  
  527.     (*WindowFunctions[*pSelection])(dest, src, m);
  528.  
  529.     LocalUnlock(hSelection);
  530. }
  531.